/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include <omp.h>

#include <file_文件名数据.h>

#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>

#include "底层绘图/S_纹理.h"
#include "底层绘图/底层绘图框架.h"
#include "底层绘图/intern/绘图框架.h"

#include "纹理/纹理.h"




void f_tex_加载图像文件(S_纹理添加列队& 纹理) {
	uvec3 维度 = { 0,0, 1 };

	纹理.m_纹理对象->m_像素 = stbi_load(纹理.m_加载路径.c_str(),
								(int32*)&纹理.m_新大小.x,
								(int32*)&纹理.m_新大小.y,
								(int32*)&纹理.m_新大小.z,
								4);

	纹理.m_新大小.z = 1;
	纹理.m_加载到内存完成 = true;
	纹理.m_纹理对象->m_其它库加载纹理 = true;
}

void f_tex_加载图像到GPU(S_纹理添加列队& 列队, S_结构指针 命令缓存) {
	f_tex_修改大小(列队.m_纹理对象, 列队.m_新大小, false);
	f_tex_填充纹理数据(列队.m_纹理对象, (const uint8*)(列队.m_纹理对象->m_像素), sizeof(ubvec4), 列队.m_纹理对象->m_Size, 命令缓存);
}

void f_tex_从文件加载纹理到显卡(S_纹理* tex, std::string path, S_结构指针 命令缓存) {
	uvec3 维度 = { 0, 0, 1 };

	stbi_uc* data_p = stbi_load(path.c_str(), (int32*)&维度.x, (int32*)&维度.y, (int32*)&维度.z, 4);
	switch (维度.z) {
		case 1: {
			break;
		}
		case 2: {
			break;
		}
		case 3: {
			break;
		}
		case 4: {
			break;
		}
	}

	if(!维度.x || !维度.y && !data_p) {
		DEF_记录日志("从文件加载纹理到显卡失败 大小错误 A" + std::to_string(uint64(data_p)));
		return;
	}
	维度.z = 1;
	//lodepng_decode_file((uint8**)&data_p, &维度.x, &维度.y, path.c_str(), LodePNGColorType::LCT_RGBA, 8);
	//std::vector<ubvec4> 变换像素(维度.x* 维度.y);
	//uint8 *变换像素 = nullptr;
	//stbir_resize_uint8(data_p, 维度.x, 维度.y, 0, (uint8*)变换像素.data(), 维度.x, 维度.y, 0, 4);
	

	f_tex_修改大小(tex, 维度, false);
	f_tex_填充纹理数据(tex, (const uint8*)data_p, sizeof(ubvec4), 维度, 命令缓存);

	stbi_image_free(data_p);
	//free(data_p);
}

void f_tex_从文件填充纹理(S_纹理* tex, std::string path, S_子集绘图命令* 绘图命令) {
	uvec3 维度 = { 0, 0, 1 };
	stbi_uc* data_p = stbi_load(path.c_str(), (int32*)&维度.x, (int32*)&维度.y, (int32*)&维度.z, 4);

	if (!维度.x || !维度.y) {
		DEF_记录日志("从文件加载纹理到显卡失败 大小错误 B" + std::to_string(uint64(data_p)));
		return;
	}
	维度.z = 1;


	f_tex_修改大小(tex, 维度, false);
	f_tex_填充纹理数据(tex, (const uint8*)data_p, sizeof(ubvec4), 维度, S_绘图框架::g_资源加载管道->m_命令缓存[0]);

	stbi_image_free(data_p);

}

void f_tex_从文件加载纹理(S_纹理* tex, const S_Props& path, int32 通道数量) {
	//uvec3 维度 = { 0,0, 1 };
	auto s = f_prop_LineStr(path);
	if (f_file_文件是否存在(s)) {
		tex->m_通道数量 = 通道数量;

		
		int32 读取到的通道数量 = 0;
		stbi_uc* data_p = stbi_load(f_str_u16_to_u8(s).c_str(), (int32*)&(tex->m_Size.x), (int32*)&(tex->m_Size.y), &读取到的通道数量, 通道数量);

		switch (读取到的通道数量) {	
			case 0: {
				break;
			}
			case 1: {
				break;
			}
			case 2: {
				break;
			}
			case 3: {
				break;
			}
			case 4: {
				break;
			}
		}
		tex->m_像素 = data_p;
	}
	else {
		tex->m_像素 = calloc(tex->m_Size.x * tex->m_Size.y, sizeof(S_RGBA8UI) * 4);
		tex->m_通道数量 = 通道数量;
	}
}

void f_tex_纹理上传到显卡(S_纹理* tex) {

}

static void f_纹理写入到文件(uvec2 size, const std::string& path, const std::u16string& 格式, int32 通道数量, int32 位宽, void* data) {
	
	if (格式 == u"png") {
		//stbi_write_png(path.c_str(), size.x, size.y, 通道数量, data, size.x * 位宽);
		stbi_write_png(path.c_str(), size.x, size.y, 通道数量, data, 0);
	}
	else if (格式 == u"jpg") {
		stbi_write_jpg(path.c_str(), size.x, size.y, 通道数量, data, 95);
	}
	else if (格式 == u"tga") {
		stbi_write_tga(path.c_str(), size.x, size.y, 通道数量, data);
	}
	else if (格式 == u"bmp") {
		stbi_write_bmp(path.c_str(), size.x, size.y, 通道数量, data);
	}
	else if (格式 == u"hdr") {
		stbi_write_hdr(path.c_str(), size.x, size.y, 通道数量, (float32*)data);
	}
	//stbi_write_png_16("output.png", 10, 10, 4, 0, 10 * 4 * sizeof(unsigned short));
}

static void f_纹理写入到文件(S_纹理* tex, void* inData, const std::u16string& 格式, int32 通道数量, int32 位宽, const std::string& path) {
	uvec2 分辨率 = _uVec2(tex->m_Size);

	if (格式 != u"hdr") {
		switch (位宽) {
			case 4: {
				
				switch (tex->m_格式) {
					case E_纹理格式::e_tf_RGBA32: {
						std::vector<S_RGBA8UI> 像素转换(分辨率.x * 分辨率.y);
						vec4* pix = (vec4*)(inData);

						omp_set_num_threads(4);
					#pragma omp parallel for
						for (int32 y = 0; y < 分辨率.y; ++y) {
							for (uint32 x = 0; x < 分辨率.x; ++x) {
								uint64 index = 分辨率.x * y + x;
								S_RGBA8UI color;
								color.r = pix[index].x * 255;
								color.g = pix[index].y * 255;
								color.b = pix[index].z * 255;
								color.a = pix[index].w * 255;

								像素转换[index] = color;
							}
						}
						f_纹理写入到文件(分辨率, path, 格式, 通道数量, 位宽, 像素转换.data());
						break;
					}
					case E_纹理格式::e_tf_RGB32: {
						std::vector<S_RGB8UI> 像素转换(分辨率.x * 分辨率.y);
						vec3* pix = (vec3*)(inData);

						omp_set_num_threads(4);
					#pragma omp parallel for
						for (int32 y = 0; y < 分辨率.y; ++y) {
							for (uint32 x = 0; x < 分辨率.x; ++x) {
								uint64 index = 分辨率.x * y + x;
								S_RGB8UI color;
								color.r = pix[index].x * 255;
								color.g = pix[index].y * 255;
								color.b = pix[index].z * 255;

								像素转换[index] = color;
							}
						}
						f_纹理写入到文件(分辨率, path, 格式, 通道数量, 位宽, 像素转换.data());
						break;
					}
				}
				break;
			}
			//case 1: {
			//	break;
			//}
			//case 2: {
			//	break;
			//}
			default: {
				f_纹理写入到文件(分辨率, path, 格式, 通道数量, 位宽, inData);
			}
		}
	}
	else {
		f_纹理写入到文件(分辨率, path, 格式, 通道数量, 位宽, inData);
	}
}

void f_tex_纹理写入到文件(S_纹理* tex, const std::string& path, const std::u16string& 格式, int32 通道数量, int32 位宽) {
	void* data = tex->m_像素;
	if (tex->m_像素) {
		f_纹理写入到文件(tex, tex->m_像素, 格式, 通道数量, 位宽, path);
	}
	else {
		S_板载缓存* 临时缓存 = f_buf_create板载缓存(tex->m_Ctx, E_板载缓存类型::e_SSBO, E_板载缓存类型::e_SSBO | E_板载缓存类型::e_拷贝目标, 通道数量 * 位宽, tex->m_Size.x * tex->m_Size.y);

		f_tex_读取纹理数据(tex, 临时缓存, tex->m_命令缓存);
		临时缓存->f_map();

		f_纹理写入到文件(tex, 临时缓存->m_mappedPtr, 格式, 通道数量, 位宽, path);
		
		临时缓存->f_unmap();
		f_buf_release板载缓存(临时缓存);
	}
}

void f_tex_纹理保存到文件(S_纹理* tex, const S_Props& path, const S_Props& 格式枚举, const S_Props& 保存方式) {
	auto 格式 = f_prop_enumName(格式枚举);
	auto 路径 = f_str_u16_to_u8(f_prop_LineStr(path));

	int32 通道数量 = tex->m_通道数量;


	if (f_file_文件是否存在(路径)) {
		//switch (f_prop_enum(保存方式)) {
		//	case 0: {
		//		return;
		//	}
		//	case 1: {
		//		break;
		//	}
		//	case 2: {
		//		break;
		//	}
		//	default:
		//		break;
		//}
	}
	else {
		f_file_创建目录(路径);
	}

	f_tex_纹理写入到文件(tex, 路径, 格式, 通道数量, 4);
}

void f_tex_重置2D纹理大小(S_纹理* s_tex, S_纹理* t_tex, uvec2 新大小) {
	if(!s_tex->m_像素) return;

	新大小 = vec_Max(新大小, {1,1});

	int32 通道数量 = s_tex->m_通道数量;
	auto* output_pixels = (unsigned char*)malloc(新大小.x * 新大小.y * 通道数量);

	stbir_resize_uint8((const unsigned char*)s_tex->m_像素, s_tex->m_Size.x, s_tex->m_Size.y, 0, output_pixels, 新大小.x, 新大小.y, 0, 通道数量);
	stbi_image_free(t_tex->m_像素);

	t_tex->m_像素 = output_pixels;
	t_tex->m_Size.x = 新大小.x;
	t_tex->m_Size.y = 新大小.y;

	t_tex->m_通道数量 = s_tex->m_通道数量;
}






